package findzip

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"
)

var CIPHER_TEXT, _ = regexp.Compile(`^(\\d{4}|)\\|([A-Za-z0-9=\\/\\+]{20,})\\|([A-Za-z0-9]{1,5})$`)
var CHARS = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")

func DecryptAes(text string) string {
	str := strings.Split(text, "|")
	key := str[2]
	bs := getKey(key)
	return string(DecryptBytes(str[1], bs))
}

var keys = make(map[string][]byte)

func getKey(key string) []byte {
	if bs, has := keys[key]; has {
		return bs
	}
	ts := time.Now().Unix()
	h := md5.New()
	h.Write([]byte(fmt.Sprintf("key_%s%dwoda365.com", key, ts)))
	sig := hex.EncodeToString(h.Sum(nil))

	bs := GET(fmt.Sprintf("https://rsa.woda.com/v/key_%s?ts=%d&sig=%s", key, ts, sig))
	data := &RSAData{}
	json.Unmarshal(bs, data)
	if data.Success {
		// log.Println(data.Data)
		des := make([]byte, base64.StdEncoding.EncodedLen(len(key)))
		base64.StdEncoding.Encode(des, []byte(key))
		dbs := DecryptBytes(data.Data, des)
		// log.Println(dbs)
		keys[key] = dbs

		return dbs
	}
	return nil
}

type RSAData struct {
	Data    string `json:"data"`
	Success bool   `json:"success"`
}

func GET(url string) []byte {
	client := &http.Client{}
	reqest, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Panic(err)
	}
	response, err := client.Do(reqest) //提交
	if err != nil {
		log.Panic(err)
	}
	defer response.Body.Close()
	body, err1 := ioutil.ReadAll(response.Body)
	if err1 != nil {
		log.Panic(err)
	}
	return body
}

func PathExists(path string) bool {
	if _, err := os.Stat(path); err == nil {
		return true
	}

	return false
}

func ToNumber(str string) int64 {
	log.Println(str)
	var sum int64 = 0
	l := len(str)
	for i := range str {
		sum += toInt(byte(str[l-i-1]), int64(i))
	}

	return sum
}

func toInt(b byte, position int64) int64 {
	index := bytes.IndexByte(CHARS, b)
	return int64(index) * pow(position)
}

func pow(p int64) int64 {
	if p == 0 {
		return 1
	}
	return int64(len(CHARS)) * pow(p-1)
}

func DecryptBytes(str string, key []byte) []byte {
	m := md5.New()
	m.Write(key)
	key = m.Sum(nil)
	src, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		panic(err)
	}

	var aesBlockDecrypter cipher.Block
	aesBlockDecrypter, err = aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	decrypted := make([]byte, len(src))

	aesDecrypter := cipher.NewCBCDecrypter(aesBlockDecrypter, key[:16])
	aesDecrypter.CryptBlocks(decrypted, src)

	return PKCS5Trimming(decrypted)
}
